클로드 코드 완벽 가이드 — 19장 데이터베이스 연동하기 딥다이브 학습 노트

출처: 클로드 코드 완벽 가이드 (코드팩토리 최지호) | 참고: https://github.com/codefactory-co


19장에서 다루는 내용

  • 데이터베이스 연동의 필요성 — 가짜 데이터에서 실제 DB로 전환해야 하는 이유와 적절한 시점
  • 필수 MCP 추가하기 — Supabase MCP와 Context7 MCP를 프로젝트에 등록하는 절차
  • Supabase로 마이그레이션하기 — 클로드 코드에게 계획 수립을 요청하고 자동으로 테이블 설계·마이그레이션 파일 생성까지 수행

전체 흐름도

[가짜 데이터로 MVP 완성]
    |
    v
+--------------------------------------------------+
| 1단계: 필수 MCP 추가                              |
|                                                  |
|  +-----------+          +-------------+          |
|  | Supabase  |          | Context7    |          |
|  | MCP       |          | MCP         |          |
|  +-----------+          +-------------+          |
|       |                       |                  |
|  .mcp.json 직접 편집     CLI 한 줄 등록           |
|  (PAT + Project Ref)    (인증 불필요)             |
+--------------------------------------------------+
    |
    v
+--------------------------------------------------+
| 2단계: 마이그레이션 (2-Step 전략)                  |
|                                                  |
|  Step 1: "계획만 알려줘, 코드는 작성하지마"        |
|    -> 프로젝트 분석 + 테이블 스키마 설계           |
|    -> cities 테이블 + user_preferences 테이블     |
|                                                  |
|  Step 2: "계획대로 구현해줘"                       |
|    -> 마이그레이션 SQL 자동 생성                   |
|    -> Supabase에 테이블 생성 + 코드 수정          |
+--------------------------------------------------+
    |
    v
[프론트엔드 <-> 백엔드 <-> Supabase DB 연동 완료]

선수 지식 체크리스트

  • [ ] 18장까지 가짜 데이터로 MVP 제작 완료 경험
  • [ ] Supabase 계정 생성 및 프로젝트 생성 완료
  • [ ] MCP(Model Context Protocol) 기본 개념 이해 (16장 참조)
  • [ ] SQL 기본 문법 (CREATE TABLE, PRIMARY KEY, REFERENCES 등)
  • [ ] JSON 파일 구조 읽기 (.mcp.json)

핵심 키워드

키워드 의미
데이터베이스(DB) 사용자 정보, 게시글, 로그 등 데이터를 영구적으로 저장하고 불러오는 저장소. 없으면 앱이 "기억"을 못 한다
Supabase PostgreSQL 기반 오픈소스 백엔드 서비스. 무료 티어가 있고 MCP가 잘 구현되어 있어 바이브 코딩에 적합
MCP (Model Context Protocol) AI 모델이 외부 도구/서비스와 통신하기 위한 표준 프로토콜. Supabase MCP를 통해 DB를 직접 조작 가능
PAT (Personal Access Token) Supabase 계정에서 발급하는 인증 토큰. MCP가 Supabase에 접근할 때 신분증 역할
Project Ref Supabase 프로젝트의 고유 식별자. Settings > General > Project ID에서 확인
.mcp.json 프로젝트 루트에 위치하는 MCP 서버 설정 파일. mcpServers 객체에 각 MCP 서버 정보를 등록
Context7 MCP Upstash에서 제공하는 MCP. 최신 라이브러리 문서를 AI에게 실시간으로 제공
마이그레이션(Migration) 데이터베이스 스키마(테이블 구조)를 버전 관리하며 변경하는 방법. SQL 파일로 기록
auth.users Supabase 내장 인증 시스템의 사용자 테이블. 다른 테이블에서 외래키로 참조
ON DELETE CASCADE 부모 레코드 삭제 시 자식 레코드도 함께 삭제하는 외래키 옵션

19-1 데이터베이스 연동이 필요한 이유

한 줄 요약

프론트엔드에서 보내는 요청을 백엔드가 받아서 DB에 연결해주는 구조가 웹 앱의 기본 골격이며, 가짜 데이터로 MVP를 먼저 완성한 뒤 실제 DB로 전환하는 것이 효율적이다.

쉬운 설명 — 메모장 비유

데이터베이스 없는 앱 = 기억력이 없는 사람
  -> 버튼을 눌러 저장해도, 새로고침하면 모든 데이터가 사라짐
  -> 다른 기기에서는 아예 볼 수 없음

데이터베이스 있는 앱 = 메모장을 가진 사람
  -> 저장하면 메모장(DB)에 기록
  -> 나중에 다시 열어도, 다른 기기에서 열어도 기록이 남아 있음

웹 앱의 기본 구조:
  프론트엔드(화면) --요청--> 백엔드(서버) --저장/조회--> DB(저장소)

가짜 데이터 vs 실제 DB

비교 항목 가짜 데이터 (이전까지) 실제 DB (19장부터)
데이터 위치 코드 안 (JSON 변수) 외부 DB 서버 (Supabase)
새로고침 데이터 초기화됨 데이터 유지됨
사용자별 저장 불가능 가능 (인증 연동)
멀티 기기 불가능 (localStorage) 가능 (서버 저장)
용도 MVP 프로토타입 확인 실제 서비스 운영

실무 예제 — 왜 가짜 데이터를 먼저 쓸까?

❌ 처음부터 DB 연동하는 경우:
  DB 설계 + 프론트엔드 + 백엔드를 동시에 고민
  -> 레이어가 섞여 복잡도 폭발
  -> 버그가 어느 레이어에서 난 건지 찾기 어려움
  -> "DB 문제인가? API 문제인가? UI 문제인가?" 혼란

✅ 가짜 데이터로 MVP 먼저 만드는 경우 (저자 추천):
  프론트엔드 완성 -> 동작 확인 -> 그 다음 DB 연동
  -> 레이어별로 명확히 나뉘어 문제 추적 쉬움
  -> "작업 레이어가 명확히 나뉘어 더 좋은 결과가 나온다"

핵심 체크포인트

  • [ ] 프론트엔드 -> 백엔드 -> DB 3계층 구조를 설명할 수 있는가?
  • [ ] 가짜 데이터로 MVP를 먼저 만든 후 DB를 연동하는 이유를 아는가?
  • [ ] DB가 없는 앱의 한계점 3가지 이상 말할 수 있는가?

19-2 필수 MCP 추가하기

한 줄 요약

Supabase MCP와 Context7 MCP 두 가지를 프로젝트에 등록하면, 클로드 코드가 데이터베이스를 직접 다루고 최신 문서도 참조할 수 있게 된다.

쉬운 설명 — 통역사 비유

MCP = 클로드 코드와 외부 서비스 사이의 "통역사"

Supabase MCP (DB 전문 통역사):
  클로드 코드 <-> [Supabase MCP] <-> Supabase DB
  "테이블 만들어줘" -> MCP가 SQL로 번역 -> DB에 실행

Context7 MCP (문서 전문 통역사):
  클로드 코드 <-> [Context7 MCP] <-> 최신 공식 문서
  "Supabase 최신 API 알려줘" -> 공식 문서 검색 -> 최신 정보 제공

왜 두 개 다 필요할까?
  Supabase MCP만 있으면: DB는 다루지만 최신 API를 모를 수 있음
  Context7 MCP만 있으면: 문서는 알지만 DB를 직접 조작 못함
  둘 다 있으면: 최신 정보 + 직접 실행 = 최적의 조합!

Supabase를 선택한 이유

이 책에서 Supabase를 선택한 2가지 이유:
  1. 무료 티어를 활용할 수 있다 (비용 부담 없이 학습 가능)
  2. MCP가 잘 구현되어 있다 (클로드 코드와 연동이 매끄러움)

Supabase MCP 설정 절차 (5단계)

Step 01: 프로젝트 루트에 .mcp.json 파일 생성
Step 02: mcpServers 객체에 supabase 서버 정보 추가
         - command: "npx"
         - args: ["-y", "@supabase/mcp-server-supabase@latest",
                  "--read-only", "--project-ref=<project-ref>"]
         - env: { "SUPABASE_ACCESS_TOKEN": "<personal-access-token>" }
Step 03: PAT(Personal Access Token) 발급
         supabase.com/dashboard/account/tokens 접속
         -> Generate New Token -> 이름 입력 (예: "Claude Code MCP")
         -> 토큰 복사 (한 번만 보여주므로 반드시 저장!)
Step 04: Project Ref 확인
         Supabase 대시보드 -> Settings > General > Project ID 복사
Step 05: .mcp.json의 <personal-access-token>과 <project-ref>를 실제 값으로 치환

.mcp.json 설정 예시

{
  "mcpServers": {
    "supabase": {
      "command": "npx",
      "args": [
        "-y",
        "@supabase/mcp-server-supabase@latest",
        "--read-only",
        "--project-ref=dienjsndfhurexnhyrrt"
      ],
      "env": {
        "SUPABASE_ACCESS_TOKEN": "sbp_629ad31617d8e815eb0ff1f2d3ed52b1f32b7bcd"
      }
    }
  }
}

Context7 MCP 등록

# CLI 한 줄로 등록 (프로젝트 수준, -s project)
claude mcp add context7 -s project -- npx -y @upstash/context7-mcp

등록 후 .mcp.json에 자동으로 context7 서버가 추가된다.

{
  "mcpServers": {
    "supabase": { ... },
    "context7": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@upstash/context7-mcp"],
      "env": {}
    }
  }
}

MCP 등록 확인 방법

/mcp 명령어 실행 시:
  ✅ context7  — 활성화 상태
  ✅ supabase  — 활성화 상태
  -> 둘 다 활성화되어 있어야 정상!

실무 예제 — 보안 주의사항

❌ 잘못된 방법:
  .mcp.json에 PAT를 하드코딩한 채로 Git에 커밋
  -> 토큰이 공개되어 보안 사고 발생!

✅ 올바른 방법:
  방법 1: .mcp.json을 .gitignore에 추가
  방법 2: 환경 변수로 토큰을 관리
  -> 민감한 인증 정보는 절대 Git에 올리지 않는다

Supabase MCP vs Context7 MCP 비교

비교 항목 Supabase MCP Context7 MCP
등록 방법 .mcp.json 직접 편집 CLI 명령어 한 줄
인증 필요 O (PAT + Project Ref) X (인증 불필요)
역할 DB 직접 조작 (테이블 생성, 쿼리) 최신 라이브러리 문서 제공
패키지 @supabase/mcp-server-supabase @upstash/context7-mcp
제공처 Supabase 공식 Upstash

핵심 체크포인트

  • [ ] .mcp.json 파일의 구조(mcpServers > 서버명 > command/args/env)를 이해하는가?
  • [ ] PAT는 어디서 발급하고, Project Ref는 어디서 확인하는가?
  • [ ] Context7 MCP를 CLI로 등록하는 명령어를 아는가?
  • [ ] 두 MCP의 역할 차이를 설명할 수 있는가?
  • [ ] .mcp.json을 Git에 올리면 안 되는 이유를 아는가?

19-3 Supabase로 마이그레이션하기

한 줄 요약

클로드 코드에게 먼저 "계획만 세워줘"로 프로젝트를 분석시킨 뒤, "계획대로 구현해줘"로 자동 마이그레이션을 실행하는 2-Step 전략을 사용한다.

쉬운 설명 — 이사 비유

마이그레이션 = 데이터의 "이사"

가짜 데이터(임시 집) -> 실제 DB(새 집)로 이사

이사 계획서 = 마이그레이션 파일 (SQL)
  1. 새 집 구조 설계 (CREATE TABLE)
  2. 가구 배치 (컬럼 정의: name, cost, likes 등)
  3. 관계 설정 (외래키: 이 사람은 이 방 거주자!)
  4. 짐 옮기기 (데이터 삽입)

❌ 이사 계획 없이 짐 옮기면: 가구 위치 엉망, 물건 분실
✅ 이사 계획 세우고 짐 옮기면: 체계적으로 완료

마이그레이션 2-Step 전략

┌─────────────────────────────────────────────────────────┐
│ Step 1: 계획 수립 (코드 작성 없이 계획만 요청)            │
│                                                         │
│ 프롬프트:                                                │
│ "context7과 Supabase MCP를 사용해서 현재 웹사이트를      │
│  Supabase 백엔드와 연동하려면 어떻게 해야 하는지         │
│  계획을 알려줘. 계획만 알려주고 코드는 아직 작성하지마."   │
│                                                         │
│ -> 클로드 코드가 프로젝트 구조를 분석                     │
│ -> 테이블 스키마를 설계해서 보여줌                        │
│ -> 마음에 안 들면 수정 요청 가능!                         │
└─────────────────────────────────────────────────────────┘
                        |
                        v
┌─────────────────────────────────────────────────────────┐
│ Step 2: 구현 실행                                        │
│                                                         │
│ 프롬프트: "계획대로 구현해줘"                              │
│                                                         │
│ -> 마이그레이션 파일 자동 생성 (SQL)                      │
│ -> Supabase에 테이블 생성                                │
│ -> 프론트엔드/백엔드 코드 수정                            │
└─────────────────────────────────────────────────────────┘

왜 2단계로 나눌까?

DB 작업 = 되돌리기 어려운 중요한 작업

❌ 바로 "구현해줘":
  테이블 구조가 잘못 설계되면 나중에 수정이 복잡
  데이터가 들어간 후 구조 변경 = 매우 위험

✅ "계획 먼저 -> 확인 -> 구현":
  테이블 설계를 눈으로 확인 후 진행
  잘못된 부분 발견하면 코드 작성 전에 수정
  안전하고 체계적!

클로드 코드가 분석한 프로젝트 상태

기존 설정:
  - Supabase 프로젝트 연결됨
  - Next.js 15.3.5 + App Router
  - 인증 미들웨어 구성됨
  - 클라이언트/서버 Supabase 유틸리티 존재

현재 데이터 구조:
  - 20개 도시 정적 데이터 (JSON)        -> cities 테이블로 이사
  - 사용자 선호도 (localStorage 저장)   -> user_preferences 테이블로 이사
  - 도시별 8개 점수 체계                -> jsonb 컬럼으로 저장

Supabase MCP가 자동 설계한 테이블 구조

-- 1. Cities 테이블 (도시 정보)
cities (
  id integer PRIMARY KEY,          -- 도시 고유 번호
  name text NOT NULL,              -- 도시 이름 (필수)
  tagline text,                    -- 한 줄 소개
  cost text,                       -- 생활비
  internet text,                   -- 인터넷 속도
  likes integer DEFAULT 0,         -- 좋아요 수 (기본값 0)
  dislikes integer DEFAULT 0,      -- 싫어요 수 (기본값 0)
  image text,                      -- 도시 이미지 URL
  badges text[],                   -- 배열 타입: 여러 뱃지를 한 컬럼에
  scores jsonb,                    -- JSON 타입: 8개 점수를 유연하게
  region text,                     -- 지역
  budget text,                     -- 예산 범위
  environment text,                -- 환경 특성
  best_season text,                -- 최적 시즌
  description text,                -- 설명
  created_at timestamp DEFAULT now()  -- 생성 시각 (자동)
)

-- 2. User Preferences 테이블 (사용자 선호도)
public.user_preferences (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  -- Supabase MCP 덕분에 auth.users 참조를 자동으로 설정 --
  user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,
  -- ... 사용자 선호도 컬럼들 ...
)

핵심 포인트: Supabase MCP의 가치

Supabase MCP가 없었다면:
  ❌ auth.users(id) 참조 방법을 직접 찾아야 함
  ❌ 마이그레이션 파일 작성법을 수동으로 학습
  ❌ Supabase 고유 패턴을 일일이 공식 문서에서 확인
  ❌ 테이블 설계를 처음부터 직접 해야 함

Supabase MCP가 있으면:
  ✅ Supabase 맞춤형으로 백엔드 설계까지 전부 해줌
  ✅ auth.users 참조 등 Supabase 특유의 패턴 자동 적용
  ✅ 마이그레이션 파일까지 전부 자동 생성
  ✅ 테이블 구조가 안 보이면 "테이블 구조 보여줘"로 재확인 가능

PostgreSQL 특수 데이터 타입 정리

타입 설명 사용 예시
text[] 배열 타입 — 여러 값을 한 컬럼에 badges: ['해변도시', '저비용']
jsonb 바이너리 JSON — 유연한 키-값 scores: {"safety": 8, "wifi": 9}
uuid 범용 고유 식별자 id: 550e8400-e29b-41d4...
timestamp 날짜+시간 created_at: 2024-03-15 14:30:00

실무 예제 — 병렬 처리 주의

❌ 잘못된 방법:
  터미널 1: DB 마이그레이션 작업
  터미널 2: UI 기능 개발 (동시에)
  -> DB 구조가 바뀌면서 UI 코드와 충돌 가능!

✅ 올바른 방법:
  DB 마이그레이션 작업은 단독으로 집중해서 진행
  -> 완료 후 다른 작업 시작
  -> "데이터베이스 관련 작업은 중요한 작업이기 때문에
      다른 작업과 병렬로 처리하지 않는 걸 추천"

핵심 체크포인트

  • [ ] 마이그레이션을 "계획 -> 구현" 2단계로 나누는 이유를 아는가?
  • [ ] cities 테이블과 user_preferences 테이블의 역할 차이를 아는가?
  • [ ] user_id가 auth.users(id)를 참조하는 이유를 설명할 수 있는가?
  • [ ] ON DELETE CASCADE의 의미와 없을 때 발생하는 문제를 아는가?
  • [ ] text[], jsonb, uuid 각 타입의 용도를 구분할 수 있는가?
  • [ ] DB 작업을 병렬로 처리하면 안 되는 이유를 아는가?

연습문제

문제 1: MCP 설정 파일 완성하기 (기본)

다음 .mcp.json 파일의 빈칸 A, B, C를 채우세요.

{
  "mcpServers": {
    "supabase": {
      "command": "___A___",
      "args": [
        "-y",
        "___B___",
        "--read-only",
        "--project-ref=abc123"
      ],
      "env": {
        "___C___": "sbp_xxxx..."
      }
    }
  }
}
정답 보기 A: `npx` B: `@supabase/mcp-server-supabase@latest` C: `SUPABASE_ACCESS_TOKEN` - command는 npx(Node 패키지 실행 도구) - args에는 패키지명과 옵션을 배열로 전달 - env에는 환경 변수로 PAT를 설정

문제 2: 마이그레이션 전략 설계 (중급)

당신의 프로젝트에 products(상품)와 orders(주문) 테이블이 필요합니다. 19장의 2-Step 전략을 적용하여 클로드 코드에게 줄 프롬프트를 작성하세요.

정답 예시 **Step 1 (계획 수립):** "context7과 Supabase MCP를 사용해서 products 테이블과 orders 테이블을 설계해줘. orders는 products를 참조해야 하고, 사용자 인증도 연동해야 해. 계획만 알려주고 코드는 아직 작성하지마." **Step 2 (구현):** "계획대로 구현해줘" **핵심 포인트:** - "계획만, 코드는 아직 말고"를 명시하는 것이 핵심 - DB 작업이므로 다른 기능 개발과 병렬 처리하지 않는다 - 계획을 확인한 후 테이블 설계가 마음에 들지 않으면 수정 요청 가능

문제 3: ON DELETE CASCADE 분석 (심화)

아래 SQL에서 ON DELETE CASCADE를 제거하면 어떤 문제가 발생하는지, 그리고 기본 동작이 어떻게 되는지 설명하세요.

CREATE TABLE public.user_preferences (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL
);
정답 보기 `ON DELETE CASCADE`를 제거하면 기본값은 `ON DELETE RESTRICT`(또는 `NO ACTION`)이다. **발생하는 문제:** 1. 사용자가 탈퇴(auth.users에서 삭제)할 때, 해당 사용자의 user_preferences 레코드가 남아 있으면 **삭제 자체가 실패**한다 (RESTRICT) 2. 만약 삭제에 성공하더라도 user_preferences에 **고아 데이터(orphan data)**가 남게 된다 3. 시간이 지날수록 참조 대상이 없는 쓰레기 데이터가 쌓임 **CASCADE를 설정하면:** - 부모(auth.users) 레코드 삭제 시 자식(user_preferences) 레코드도 자동 삭제 - 데이터 정합성이 자동으로 유지됨

문제 4: MCP 역할 구분 (중급)

Supabase MCP만 설치하고 Context7 MCP를 설치하지 않으면 어떤 제한이 생기는지 설명하세요. 반대로 Context7만 있고 Supabase MCP가 없으면 어떨까요?

정답 보기 **Supabase MCP만 있는 경우:** - DB 테이블 생성, 쿼리 실행, 마이그레이션 등 직접 조작은 가능 - 하지만 Supabase의 최신 API 변경 사항을 모를 수 있음 - 오래된 API를 사용하여 에러가 발생할 가능성 **Context7 MCP만 있는 경우:** - 최신 라이브러리 문서를 참조할 수 있음 - 하지만 DB에 직접 접근하여 테이블을 만들거나 데이터를 조작할 수 없음 - 코드를 생성해줄 순 있지만 실행은 수동으로 해야 함 **결론:** 둘 다 설치해야 "최신 정보 참조 + 직접 실행"이라는 최적의 조합이 완성된다.

부록 A: 용어 사전

용어 설명
Supabase Firebase 대안 오픈소스 백엔드. PostgreSQL 기반, 인증/스토리지/실시간 기능 내장
MCP Model Context Protocol. AI 모델이 외부 도구와 통신하는 표준 프로토콜
PAT Personal Access Token. API 인증을 위한 개인 액세스 토큰. 한 번만 보여주므로 즉시 저장 필수
Project Ref Supabase 프로젝트 고유 ID. Settings > General > Project ID에서 확인
마이그레이션 DB 스키마를 버전 관리하며 변경하는 방법. SQL 파일로 기록됨
외래키(Foreign Key) 다른 테이블의 기본키를 참조하여 두 테이블의 관계를 정의하는 컬럼
ON DELETE CASCADE 부모 레코드 삭제 시 자식 레코드도 함께 삭제하는 옵션
ON DELETE RESTRICT 자식 레코드가 있으면 부모 삭제를 거부하는 옵션 (외래키 기본값)
auth.users Supabase 내장 인증 시스템의 사용자 테이블
Context7 Upstash에서 제공하는 MCP. 최신 라이브러리 문서를 AI에 실시간 제공
jsonb PostgreSQL의 바이너리 JSON 타입. 유연한 키-값 데이터 저장에 사용
text[] PostgreSQL 배열 타입. 여러 텍스트 값을 하나의 컬럼에 저장
gen_random_uuid() PostgreSQL 함수. 랜덤 UUID를 생성하여 기본키로 사용
고아 데이터(Orphan Data) 참조 대상이 삭제되어 연결이 끊긴 쓸모없는 데이터
스키마(Schema) 데이터베이스의 구조 정의. 테이블, 컬럼, 타입, 관계 등의 설계도

부록 B: 비교표

Supabase vs Firebase

비교 항목 Supabase Firebase
DB 엔진 PostgreSQL (관계형) Firestore (NoSQL)
오픈소스 O X
MCP 지원 공식 MCP 제공 비공식
무료 티어 넉넉함 제한적
SQL 지원 네이티브 SQL 쿼리 언어 별도
바이브 코딩 적합도 높음 (MCP + SQL) 보통

MCP 등록 방법 비교

비교 항목 .mcp.json 직접 편집 CLI 명령어
대표 사례 Supabase MCP Context7 MCP
인증 정보 직접 입력 필요 (PAT 등) 불필요한 경우 간편
설정 위치 .mcp.json 파일에 수동 작성 CLI가 .mcp.json에 자동 추가
적합한 상황 복잡한 설정이 필요한 MCP 단순 설정의 MCP

마이그레이션 접근 방식 비교

접근 방식 장점 단점
처음부터 DB 연동 한 번에 완성 레이어 혼재, 디버깅 어려움
가짜 데이터 -> DB 이사 (저자 추천) 레이어 분리, 단계적 검증 마이그레이션 추가 작업 필요

부록 C: 참고 자료

  • Supabase 공식 문서: https://supabase.com/docs
  • Supabase MCP 가이드: https://supabase.com/docs/guides/getting-started/mcp
  • PAT 발급 페이지: https://supabase.com/dashboard/account/tokens
  • Context7 MCP (GitHub): https://github.com/upstash/context7-mcp
  • PostgreSQL 데이터 타입: https://www.postgresql.org/docs/current/datatype.html
  • 코드팩토리 GitHub: https://github.com/codefactory-co
난이도
에피소드
질문
카드를 로딩 중...
답변

클릭하거나 Space를 눌러 뒤집기

0 / 0
학습 진도 0%
이동   Space 뒤집기   R 셔플